<!doctype html>
<html lang="zh-Hans">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
<meta name="hugo-theme" content="Axiom 0.7.1">



  <link rel="icon" type="image/png" sizes="32x32" href="/blog/">
  <link rel="icon" type="image/x-icon" href="/blog/">
  <link rel="apple-touch-icon" href="/blog/">
  <link rel="canonical" href="https://Mia-zhao.gitee.io/blog/react-%E4%B9%8B-mabox-gl/">
<link rel="preload" as="style" href="/blog/bundle.css?v=1603792187" media="all">
<link rel="stylesheet" href="/blog/bundle.css?v=1603792187" media="all">
<style>.cdata pre{color:#edf2f7;background-color:#2d3748}.cdata :not(pre)>code{color:#805ad5;background-color:#f7fafc}.chroma .err{color:#fed7d7;background-color:#9b2c2c}.chroma .hl{background-color:#4a5568}.chroma .ln{color:#a0aec0}.chroma .k,.chroma .kc,.chroma .kd,.chroma .kn,.chroma .kp,.chroma .kr{color:#63b3ed}.chroma .kt{color:#b794f4}.chroma .na{color:#f6e05e}.chroma .nb{color:#f6ad55}.chroma .nc{color:#fc8181}.chroma .no{color:#68d391}.chroma .nd{color:#fc8181}.chroma .ne{color:#fc8181}.chroma .nf{color:#f6ad55}.chroma .nt{color:#fc8181}.chroma .l{color:#b794f4}.chroma .dl,.chroma .ld,.chroma .s,.chroma .s2,.chroma .sa,.chroma .sb,.chroma .sc,.chroma .sd{color:#68d391}.chroma .se{color:#a0aec0}.chroma .s1,.chroma .sh,.chroma .si,.chroma .sr,.chroma .ss,.chroma .sx{color:#68d391}.chroma .il,.chroma .m,.chroma .mb,.chroma .mf,.chroma .mh,.chroma .mi,.chroma .mo{color:#b794f4}.chroma .o,.chroma .ow{color:#90cdf4}.chroma .p{color:#cbd5e0}.chroma .c,.chroma .c1,.chroma .ch,.chroma .cm,.chroma .cp,.chroma .cpf,.chroma .cs{color:#a0aec0}.chroma .ge{font-style:italic}.chroma .gs{font-weight:700}</style>



<title>React 之 Mapbox GL : Mia&#39;s Blog Posts</title>

<meta property="og:title" content="React 之 Mapbox GL">
<meta property="og:site_name" content="Mia&#39;s Blog Posts">
<meta property="og:url" content="https://Mia-zhao.gitee.io/blog/react-%E4%B9%8B-mabox-gl/">
<link rel="image_src" href="https://Mia-zhao.gitee.io/blog/">
<meta property="og:image" content="https://Mia-zhao.gitee.io/blog/">
<meta property="og:image:width" content="">
<meta property="og:image:height" content="">
<meta property="og:type" content="article">
<meta property="og:locale" content="zh_Hans">
<meta property="og:description" content="Mapbox GL JS 是一个用来生成地图的 JavaScript 库。要在项目里使用需要有 access token 和 mapbox style，token 需要在 mapbox 账号里创建，mapbox style 可以从gallery里添加。在 React 项目里可以用react-map-gl库来创建和操作地图。 Map Map 对象代表页面中地图，自带可以更改地图的属性和方法，也能触发用户事件。在react-map-gl中，StaticMap和InteractiveMap是对 MapboxGL 中 Map 的封装，StaticMap用来生成没有互动的静态地图，若需要支持用户互动，则用InteractiveMap（库默认的导出）。 import {Component} from &#39;react&#39;;import ReactMapGL from &#39;react-map-gl&#39;;class Map extends Component {render() {return (&amp;lt;ReactMapGLwidth={400}height={400}latitude={37.7577}longitude={-122.4376}zoom={8}onViewportChange={(viewport) =&amp;gt; {const {width, height, latitude, longitude, zoom} = viewport;// call setState and use the state to update the map.}}/&amp;gt;);}}以上提供初始 viewport，在onViewportChange中通过setState更新viewport来达到地图随缩放、移动而更新。目前高宽是固定的，若要全屏地图，可以设置height: window.">
<meta name="description" content="Mapbox GL JS 是一个用来生成地图的 JavaScript 库。要在项目里使用需要有 access token 和 mapbox style，token 需要在 mapbox 账号里创建，mapbox style 可以从gallery里添加。在 React 项目里可以用react-map-gl库来创建和操作地图。 Map Map 对象代表页面中地图，自带可以更改地图的属性和方法，也能触发用户事件。在react-map-gl中，StaticMap和InteractiveMap是对 MapboxGL 中 Map 的封装，StaticMap用来生成没有互动的静态地图，若需要支持用户互动，则用InteractiveMap（库默认的导出）。 import {Component} from &#39;react&#39;;import ReactMapGL from &#39;react-map-gl&#39;;class Map extends Component {render() {return (&amp;lt;ReactMapGLwidth={400}height={400}latitude={37.7577}longitude={-122.4376}zoom={8}onViewportChange={(viewport) =&amp;gt; {const {width, height, latitude, longitude, zoom} = viewport;// call setState and use the state to update the map.}}/&amp;gt;);}}以上提供初始 viewport，在onViewportChange中通过setState更新viewport来达到地图随缩放、移动而更新。目前高宽是固定的，若要全屏地图，可以设置height: window.">
<meta property="og:updated_time" content="2020-09-14T11:00:00Z">
<meta property="fb:app_id" content="">
<meta name="author" content="Mia Zhao">
<meta property="article:author" content="https://mia-zhao.gitee.io/">
<meta property="article:published_time" content="2020-09-14T11:00:00Z">
<meta property="article:modified_time" content="2020-09-14T11:00:00Z">
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "React 之 Mapbox GL",
  "alternativeHeadline": "Mapbox GL JS 是一个用来生成地图的 JavaScript 库。要在项目里使用需要有 access token 和 mapbox style，token 需要在 mapbox 账号里创建，mapbox style 可以从gallery里添加。在 React 项目里可以用react-map-gl库来创建和操作地图。 Map Map 对象代表页面中地图，自带可以更改地图的属性和方法，也能触发用户事件。在react-map-gl中，StaticMap和InteractiveMap是对 MapboxGL 中 Map 的封装，StaticMap用来生成没有互动的静态地图，若需要支持用户互动，则用InteractiveMap（库默认的导出）。 import {Component} from 'react';\rimport ReactMapGL from 'react-map-gl';\rclass Map extends Component {\rrender() {\rreturn (\r\u0026lt;ReactMapGL\rwidth={400}\rheight={400}\rlatitude={37.7577}\rlongitude={-122.4376}\rzoom={8}\ronViewportChange={(viewport) =\u0026gt; {\rconst {width, height, latitude, longitude, zoom} = viewport;\r// call setState and use the state to update the map.\r}}\r/\u0026gt;\r);\r}\r}\r以上提供初始 viewport，在onViewportChange中通过setState更新viewport来达到地图随缩放、移动而更新。目前高宽是固定的，若要全屏地图，可以设置height: window.",
  "url": "https://Mia-zhao.gitee.io/blog/react-%E4%B9%8B-mabox-gl/",
  "image": "https://Mia-zhao.gitee.io/blog/",
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://Mia-zhao.gitee.io/blog/react-%E4%B9%8B-mabox-gl/"
  },
  "description": "Mapbox GL JS 是一个用来生成地图的 JavaScript 库。要在项目里使用需要有 access token 和 mapbox style，token 需要在 mapbox 账号里创建，mapbox style 可以从gallery里添加。在 React 项目里可以用react-map-gl库来创建和操作地图。 Map Map 对象代表页面中地图，自带可以更改地图的属性和方法，也能触发用户事件。在react-map-gl中，StaticMap和InteractiveMap是对 MapboxGL 中 Map 的封装，StaticMap用来生成没有互动的静态地图，若需要支持用户互动，则用InteractiveMap（库默认的导出）。 import {Component} from 'react';\rimport ReactMapGL from 'react-map-gl';\rclass Map extends Component {\rrender() {\rreturn (\r\u0026lt;ReactMapGL\rwidth={400}\rheight={400}\rlatitude={37.7577}\rlongitude={-122.4376}\rzoom={8}\ronViewportChange={(viewport) =\u0026gt; {\rconst {width, height, latitude, longitude, zoom} = viewport;\r// call setState and use the state to update the map.\r}}\r/\u0026gt;\r);\r}\r}\r以上提供初始 viewport，在onViewportChange中通过setState更新viewport来达到地图随缩放、移动而更新。目前高宽是固定的，若要全屏地图，可以设置height: window.",
  "author": {
    "@type": "Person",
    "name": "Mia Zhao"
  },
  "publisher": {
    "@type": "Organization",
    "name": "Mia's Blog Posts",
    "logo": {
      "@type": "ImageObject",
      "url": "https://Mia-zhao.gitee.io/blog/"
    }
  },
  "datePublished": "2020-09-14T11:00:00Z",
  "dateModified": "2020-09-14T11:00:00Z",
  "articleBody": "\u003cp\u003eMapbox GL JS 是一个用来生成地图的 JavaScript 库。要在项目里使用需要有 access token 和 mapbox style，token 需要在 mapbox 账号里创建，mapbox style 可以从\u003ca href=\"https://www.mapbox.com/gallery/\"\u003egallery\u003c/a\u003e里添加。在 React 项目里可以用\u003ccode\u003ereact-map-gl\u003c/code\u003e库来创建和操作地图。\u003c/p\u003e\n\u003ch2 id=\"map\"\u003eMap\u003c/h2\u003e\n\u003cp\u003eMap 对象代表页面中地图，自带可以更改地图的属性和方法，也能触发用户事件。在\u003ccode\u003ereact-map-gl\u003c/code\u003e中，\u003ccode\u003eStaticMap\u003c/code\u003e和\u003ccode\u003eInteractiveMap\u003c/code\u003e是对 MapboxGL 中 Map 的封装，\u003ccode\u003eStaticMap\u003c/code\u003e用来生成没有互动的静态地图，若需要支持用户互动，则用\u003ccode\u003eInteractiveMap\u003c/code\u003e（库默认的导出）。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eimport {Component} from 'react';\r\nimport ReactMapGL from 'react-map-gl';\r\n\r\nclass Map extends Component {\r\n  render() {\r\n    return (\r\n      \u0026lt;ReactMapGL\r\n        width={400}\r\n        height={400}\r\n        latitude={37.7577}\r\n        longitude={-122.4376}\r\n        zoom={8}\r\n        onViewportChange={(viewport) =\u0026gt; {\r\n          const {width, height, latitude, longitude, zoom} = viewport;\r\n          // call `setState` and use the state to update the map.\r\n        }}\r\n      /\u0026gt;\r\n    );\r\n  }\r\n}\r\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e以上提供初始 viewport，在\u003ccode\u003eonViewportChange\u003c/code\u003e中通过\u003ccode\u003esetState\u003c/code\u003e更新\u003ccode\u003eviewport\u003c/code\u003e来达到地图随缩放、移动而更新。目前高宽是固定的，若要全屏地图，可以设置\u003ccode\u003eheight: window.innerHeight\u003c/code\u003e、\u003ccode\u003ewidth: window.innerWidth\u003c/code\u003e，但此时地图高宽并不随窗口变化而更新，需要页面刷新。添加\u003ccode\u003eresize\u003c/code\u003e监听可以及时更新地图宽高。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ecomponentDidMount() {\r\n  window.addEventListener('resize', this.updateDimensions);\r\n}\r\n\r\ncomponentWillUnmount() {\r\n  window.removeEventListener('resize', this.updateDimensions);\r\n}\r\n\r\nupdateDimensions = () =\u0026gt; {\r\n  this.setState({\r\n    viewport: { ...this.state.viewport,\r\n      height: window.innerHeight,\r\n      width: window.innerWidth\r\n    }\r\n  });\r\n}\r\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ccode\u003ereact-map-gl\u003c/code\u003e还提供 NavigationControl，若需要地址搜索条，可以用\u003ccode\u003ereact-map-gl-geocoder\u003c/code\u003e。\u003c/p\u003e\n\u003ch2 id=\"marker\"\u003eMarker\u003c/h2\u003e\n\u003cp\u003eMarker 用来在地图上添加自定义图标，多个图标生成用 \u003ca href=\"https://reactjs.org/docs/lists-and-keys.html\"\u003eReact lists and keys\u003c/a\u003e操作：\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ecoordinates.map((coord) =\u0026gt;\r\n  \u0026lt;Marker key={\u0026lt;unique-key\u0026gt;}\r\n    latitude={coord.latitude}\r\n    longitude={coord.longitude}\r\n    offsetLeft={0} offsetTop={0}\u0026gt;\r\n    \u0026lt;div\u0026gt;icon here\u0026lt;/div\u0026gt;\r\n  \u0026lt;/Marker\u0026gt;\r\n)\r\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eReact 用 key 区分、操作多个同类组件，\u003ccode\u003ekey\u003c/code\u003e需要保证唯一，在以上例子中，若\u003ccode\u003ecoordinates\u003c/code\u003e可以变，不能用\u003ccode\u003eindex\u003c/code\u003e作为\u003ccode\u003ekey\u003c/code\u003e，需要生成保证唯一的 id 作\u003ccode\u003ekey\u003c/code\u003e。\u003c/p\u003e\n\u003ch2 id=\"layer\"\u003eLayer\u003c/h2\u003e\n\u003cp\u003e生成的地图是可以导出为图片的，但是 Marker 层面不行。若需要地图及 Marker，一个解决办法是新增 Layer 层绘制 Marker 并导出然后从地图上移除 Layer。Map 需要添加属性\u003ccode\u003epreserveDrawingBuffer\u003c/code\u003e才能导出为图片。\u003c/p\u003e"
}
</script>

<link rel="preload" as="script" href="/blog/bundle.js?v=1603792187">


</head>
<body>

  <header id="nav" class="header">
  <div class="ax-l-i max-w-6xl">
    <div class="ax-logo">
      <a class="block" href="/blog/" title="Mia&#39;s Blog Posts"><span class="font-semibold text-raven-900">Mia's Blog Posts</span></a>
    </div>
    <div class="ax-user">
      <a class="p-2 w-8 h-8 block text-raven-500 hover:text-gray-800 focus:text-gray-800 focus:outline-none" target="_blank" rel="noopener nofollow" href="https://www.google.com/search?q=site:https://Mia-zhao.gitee.io/blog/" title="Search">
        <svg class="fill-current" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M2.67 12.804c0-5.6 4.544-10.134 10.133-10.134s10.134 4.544 10.134 10.134-4.544 10.133-10.134 10.133S2.67 18.393 2.67 12.804zm28.943 16.923l-8.868-8.868c4.287-5.3 3.68-13.012-1.378-17.57S8.564-1.066 3.75 3.75s-5.017 12.558-.46 17.618 12.28 5.665 17.57 1.378l8.868 8.868a1.33 1.33 0 0 0 2.231-.597c.123-.46-.008-.952-.345-1.29h0z"/></svg>

      </a>
      <a class="p-2 block text-base leading-none text-raven-500 hover:text-gray-800 focus:text-gray-800 focus:outline-none" href="/blog/posts/">
        Posts
      </a>
    </div>
  </div>

  
</header>

  <main>
<div class="default-single">
  <div class="ax-title ax-l-o">
    <div class="ax-l-i max-w-680">
      <h1 class="post-title font-content-title font-normal leading-tight tracking-default text-40">React 之 Mapbox GL</h1>

      <div class="ax-meta flex items-center mt-5">
        <div class="flex-grow min-w-0">
          <div class="flex items-center">
  <div class="flex-shrink-0">
    <img
    class="w-12 h-12 sm:w-14 sm:h-14 object-cover p-3px rounded-full border border-blue-300"
    src="/blog/images/author/default.webp"
    alt="Mia Zhao">
  </div>
  <div class="flex-shrink-0 ml-2 leading-tight font-content-sans">
    <a class="block text-sm text-raven-800 hover:text-raven-900 hover:underline focus:underline" target="_blank" rel="noopener nofollow" title="Mia Zhao" href="https://mia-zhao.gitee.io/">Mia Zhao</a>
    <time class="text-sm text-raven-500" datetime="2020-09-14T11:00:00Z">Sep 14, 2020 7:00PM</time>
  </div>
</div>

        </div>
        <div>
          <div class="flex items-center">
  <a class="flex-shrink-0 block text-raven-800 hover:text-raven-900" target="_blank" rel="noopener nofollow" title="Share on Twitter" href="https://twitter.com/intent/tweet?text=React%20%e4%b9%8b%20Mapbox%20GL%20by%20%40%25%21s%28%3cnil%3e%29%20https%3a%2f%2fMia-zhao.gitee.io%2fblog%2freact-%25E4%25B9%258B-mabox-gl%2f"><svg class="w-6 h-6 fill-current" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M32 6.078c-1.2.522-2.458.868-3.78 1.036 1.36-.812 2.398-2.088 2.886-3.626a13.11 13.11 0 0 1-4.16 1.588C25.742 3.794 24.026 3 22.154 3a6.56 6.56 0 0 0-6.556 6.562c0 .52.044 1.02.152 1.496-5.454-.266-10.28-2.88-13.522-6.862-.566.982-.898 2.106-.898 3.316a6.57 6.57 0 0 0 2.914 5.452 6.48 6.48 0 0 1-2.964-.808v.072c0 3.188 2.274 5.836 5.256 6.446-.534.146-1.116.216-1.72.216-.42 0-.844-.024-1.242-.112.85 2.598 3.262 4.508 6.13 4.57a13.18 13.18 0 0 1-8.134 2.798c-.538 0-1.054-.024-1.57-.1C2.906 27.93 6.35 29 10.064 29c12.072 0 18.672-10 18.672-18.668 0-.3-.01-.57-.024-.848C30.014 8.56 31.108 7.406 32 6.078z"/></svg>
</a>
  <a class="ml-3 flex-shrink-0 block text-raven-800 hover:text-raven-900" target="_blank" rel="noopener nofollow" title="Share on Facebook" href="https://www.facebook.com/dialog/share?app_id=&display=page&href=https%3a%2f%2fMia-zhao.gitee.io%2fblog%2freact-%25E4%25B9%258B-mabox-gl%2f"><svg class="w-6 h-6 fill-current" viewBox="-7 -3.5 39 39" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M30.234 0H1.765C.8.001 0 .79 0 1.766v28.47C.001 31.2.79 32 1.766 32h15.328V19.625h-4.156V14.78h4.156v-3.564c0-4.134 2.523-6.384 6.21-6.384 1.766 0 3.284.13 3.726.2v4.32h-2.543c-2.006 0-2.394.953-2.394 2.352v3.085h4.797l-.625 4.844h-4.172V32h8.14C31.21 32 32 31.2 32 30.234V1.765C32 .8 31.21 0 30.234 0z"/></svg>
</a>
</div>

        </div>
      </div>
    </div>
  </div><div class="ax-content ax-l-o">
    <div class="ax-l-i max-w-680">
      <article class="cdata">
<p>Mapbox GL JS 是一个用来生成地图的 JavaScript 库。要在项目里使用需要有 access token 和 mapbox style，token 需要在 mapbox 账号里创建，mapbox style 可以从<a href="https://www.mapbox.com/gallery/">gallery</a>里添加。在 React 项目里可以用<code>react-map-gl</code>库来创建和操作地图。</p>
<h2 id="map">Map</h2>
<p>Map 对象代表页面中地图，自带可以更改地图的属性和方法，也能触发用户事件。在<code>react-map-gl</code>中，<code>StaticMap</code>和<code>InteractiveMap</code>是对 MapboxGL 中 Map 的封装，<code>StaticMap</code>用来生成没有互动的静态地图，若需要支持用户互动，则用<code>InteractiveMap</code>（库默认的导出）。</p>
<pre><code>import {Component} from 'react';
import ReactMapGL from 'react-map-gl';

class Map extends Component {
  render() {
    return (
      &lt;ReactMapGL
        width={400}
        height={400}
        latitude={37.7577}
        longitude={-122.4376}
        zoom={8}
        onViewportChange={(viewport) =&gt; {
          const {width, height, latitude, longitude, zoom} = viewport;
          // call `setState` and use the state to update the map.
        }}
      /&gt;
    );
  }
}
</code></pre><p>以上提供初始 viewport，在<code>onViewportChange</code>中通过<code>setState</code>更新<code>viewport</code>来达到地图随缩放、移动而更新。目前高宽是固定的，若要全屏地图，可以设置<code>height: window.innerHeight</code>、<code>width: window.innerWidth</code>，但此时地图高宽并不随窗口变化而更新，需要页面刷新。添加<code>resize</code>监听可以及时更新地图宽高。</p>
<pre><code>componentDidMount() {
  window.addEventListener('resize', this.updateDimensions);
}

componentWillUnmount() {
  window.removeEventListener('resize', this.updateDimensions);
}

updateDimensions = () =&gt; {
  this.setState({
    viewport: { ...this.state.viewport,
      height: window.innerHeight,
      width: window.innerWidth
    }
  });
}
</code></pre><p><code>react-map-gl</code>还提供 NavigationControl，若需要地址搜索条，可以用<code>react-map-gl-geocoder</code>。</p>
<h2 id="marker">Marker</h2>
<p>Marker 用来在地图上添加自定义图标，多个图标生成用 <a href="https://reactjs.org/docs/lists-and-keys.html">React lists and keys</a>操作：</p>
<pre><code>coordinates.map((coord) =&gt;
  &lt;Marker key={&lt;unique-key&gt;}
    latitude={coord.latitude}
    longitude={coord.longitude}
    offsetLeft={0} offsetTop={0}&gt;
    &lt;div&gt;icon here&lt;/div&gt;
  &lt;/Marker&gt;
)
</code></pre><p>React 用 key 区分、操作多个同类组件，<code>key</code>需要保证唯一，在以上例子中，若<code>coordinates</code>可以变，不能用<code>index</code>作为<code>key</code>，需要生成保证唯一的 id 作<code>key</code>。</p>
<h2 id="layer">Layer</h2>
<p>生成的地图是可以导出为图片的，但是 Marker 层面不行。若需要地图及 Marker，一个解决办法是新增 Layer 层绘制 Marker 并导出然后从地图上移除 Layer。Map 需要添加属性<code>preserveDrawingBuffer</code>才能导出为图片。</p>

      </article>
      

      

    </div>
  </div>
</div>

  </main>
  <footer class="footer">
  <div class="ax-l-i max-w-6xl">
    <nav class="flex items-center justify-center">
      <a class="ml-3 first:ml-0 text-sm text-gray-600 hover:text-gray-800" href="/blog/posts/">Posts</a>
      <a class="ml-3 first:ml-0 text-sm text-gray-600 hover:text-gray-800" href="/blog/contact/">Contact</a>
    </nav>

    <div class="footer-copyright text-sm text-center text-gray-500 mt-4">
      &#169; -2020 Mia&#39;s Blog Posts
    </div>
    <div class="text-sm sm:text-xs text-center text-gray-500 mt-2">
      Powered by <a href="https://www.axiomtheme.com/?utm_source=theme-footer&utm_medium=website&utm_campaign=referral">Axiom</a>
    </div>
  </div>
</footer>

<script src="/blog/bundle.js?v=1603792187"></script>


</body>
</html>
